/*
 *  segmentation
 *
 *  license: GPL2
 *  Copyright (C) i@liufang.org.cn
 *  Author: fang.liu
 */

#include <stdlib.h>
#include <fcntl.h>
#include <unistd.h>
#include <event2/event.h>
#include "segmentation.h"

#define PORT 12345
#define BACKLOG 5
#define MEM_SIZE 4096
#define PID_FILE "/var/run/segmentation.pid"

struct event_base *base;

static void save_pid(const char *pid_file) {
    FILE *fp;

    if ((fp = fopen(pid_file, "w")) == NULL) {
        printf("Could not open the pid file %s for writing", pid_file);
        return;
    }

    fprintf(fp,"%ld\n", (long)getpid());

    if (fclose(fp) == -1) {
    	printf("Could not close the pid file %s", pid_file);
    }
}


int main(int argc, char** argv)
{
	int opt;
	char *opt_string = "vhnw:";
	char *word_file = "/tmp/seg.txt";
	char *tmp;
	int is_net = 0;
	//有传递参数, 进行参数处理
	if(argc > 1) {
		while ((opt = getopt(argc, argv, opt_string)) != -1) {
			switch (opt) {
				case 'v':
					printf("segmentation version: ");
					printf(SEGMENTATION_VERSION);
					printf("\r\n");
					return 0;
					break;
				case 'w':
					word_file = optarg;
					break;
				case 'n':
					is_net = 1;
					break;
				case 'h':
				default:
					printf("segmentation help: \r\n");
					printf("-h segmentation help\r\n");
					printf("-v segmentation version\r\n");
					printf("-w word file path\r\n");
					printf("-n run with server");
					return 0;
			}
		}
	}

	init_index(word_file);

	if(is_net == 1) {
		//退出主进程后台运行程序
		if(fork() > 0) {
			exit(0);
		}
		//开启分词服务监听, 通过套接字方式进行网络请求分词
		seg_server();
	} else {
		//console
		result* r = seg(argv[argc-1]);
		print_result(r);
		free_result(r);
	}
	return 0;
}

/**
 * 接受处理客户端请求
 */
void on_read(int sock, short event, void* arg)
{
	char buf[MEM_SIZE];
	seg_str* result_str;
	result* r;
	int n;

	if(event == EV_TIMEOUT) {
		//ignore
		return;
	}

	while((n = read(sock, buf, MEM_SIZE))>0) {
		if(n < MEM_SIZE) {
			buf[n] = '\0';
		}
		r = seg(buf);
		//write to client
		result_str = NULL;
		result_str = string_result(r);
		if(result_str != NULL) {
			write(sock, result_str->str, result_str->len+1);
			//puts(result_str->str);
		}
		free(result_str->str);
		free(result_str);
		//print_result(r);
		free_result(r);
		if(n < MEM_SIZE) {
			break;
		}
	}
	//无数据返回, 客户端关闭或者  延时严重
	if(n==0) {
		puts("关闭连接");
		close(sock);
	}
}

/**
 * 接受客户端连接
 */
void on_accept(int sock, short event, void* arg)
{
	struct sockaddr_in cli_addr;
	int newfd, sin_size;
	//struct timeval one_seconds = {1,0};
	sin_size = sizeof(struct sockaddr_in);
	newfd = accept(sock, (struct sockaddr*)&cli_addr, &sin_size);
	struct event* read_ev = event_new(base, newfd, EV_TIMEOUT|EV_READ|EV_PERSIST, on_read, NULL);
	//event_base_set(base, read_ev);
	event_add(read_ev, NULL);
}


void seg_server()
{
	struct sockaddr_in my_addr;
	int sock;

	sock = socket(AF_INET, SOCK_STREAM, 0);
	int yes = 1;
	setsockopt(sock, SOL_SOCKET, SO_REUSEADDR, &yes, sizeof(int));
	memset(&my_addr, 0, sizeof(my_addr));
	my_addr.sin_family = AF_INET;
	my_addr.sin_port = htons(PORT);
	my_addr.sin_addr.s_addr = INADDR_ANY;
	bind(sock, (struct sockaddr*)&my_addr, sizeof(struct sockaddr));
	listen(sock, BACKLOG);
	puts("=================================================================\n");
	puts("=============            server runing at port:12345     ========\n");
	puts("=================================================================\n");
	//save pid file
	save_pid(PID_FILE);
	//loop event
    struct event *seg_ev;
    //struct timeval five_seconds = {5,0};
    base = event_base_new();
    seg_ev = event_new(base, sock, EV_TIMEOUT|EV_READ|EV_PERSIST, on_accept, NULL);
    event_add(seg_ev, NULL);
    event_base_dispatch(base);
}



